﻿using System;
using System.Text;
using System.Windows.Forms;
using System.IO;
using ReplaceTool.Properties;
using ReplaceTool;
using System.Collections.Generic;

namespace SubstituteTool
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Settings.Default.Reload();
            initCharset();
            initControls();
            flowLayoutPanel1_Resize(sender, e);
            repaintControls();
        }
        private void Form1_Shown(object sender, EventArgs e)
        {
            textFind.Focus();
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Settings.Default.checkNumber = checkNumber.Checked;
            Settings.Default.numericStart = (int)numericStart.Value;
            Settings.Default.numericDigit = (int)numericDigit.Value;
            Settings.Default.columnName_width = listFiles.Columns[0].Width;
            Settings.Default.columnDate_width = listFiles.Columns[1].Width;
            Settings.Default.columnSize_width = listFiles.Columns[2].Width;
            Settings.Default.columnPath_width = listFiles.Columns[pathIndex].Width;

            Settings.Default.Save();
        }
        private void flowLayoutPanel1_Resize(object sender, EventArgs e)
        {
            fitWidth(flowLayoutPanel2);
            fitWidth(flowLayoutPanel3);
        }
        private void flowLayoutPanel2_Resize(object sender, EventArgs e)
        {
            fitWidth(textFind);
        }
        private void flowLayoutPanel3_Resize(object sender, EventArgs e)
        {
            fitWidth(textReplace);
            fitWidth(textSample);
        }
        private void textFind_TextChanged(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void textReplace_TextChanged(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void checkNumber_CheckedChanged(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void numericStart_ValueChanged(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void numericDigit_ValueChanged(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void menuOpenFiles_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                appendFiles(openFileDialog.FileNames);
            }
        }
        private void menuReplace_Click(object sender, EventArgs e)
        {
            replaceAll();
        }
        private void menuOpen_Click(object sender, EventArgs e)
        {
            openListFiles();
        }
        private void menuUp_Click(object sender, EventArgs e)
        {
            int count = listFiles.Items.Count;
            for (int i = 0; i < count; i++)
            {
                if (i != 0 && listFiles.Items[i].Selected)
                {
                    if (!listFiles.Items[i - 1].Selected)
                    {
                        changeItemPos(i - 1, i);
                    }
                }
            }
        }
        private void menuDown_Click(object sender, EventArgs e)
        {
            for (int i = listFiles.Items.Count - 1; i >= 0; i--)
            {
                if (i != listFiles.Items.Count - 1 && listFiles.Items[i].Selected)
                {
                    if (!listFiles.Items[i + 1].Selected)
                    {
                        changeItemPos(i, i + 1);
                    }
                }
            }
        }
        private void menuDelete_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(
                Resources.Form1_Message_M001.Replace("{selected}", "" + listFiles.SelectedItems.Count),
                Resources.Form1_Message_M002,
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Question) == DialogResult.Yes)
            {
                IList<ListViewItem> items = copySelectedItems();
                foreach (ListViewItem item in items)
                {
                    listFiles.Items.Remove(item);
                }
            }
            repaintControls();
        }
        private void menuSelectAll_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in listFiles.Items)
            {
                item.Selected = true;
            }
            listFiles.Focus();
        }
        private void listFiles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            repaintControls();
        }
        private void listFiles_DragEnter(object sender, DragEventArgs e)
        {
            Console.WriteLine("listFiles_DragEnter");
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;

            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }
        private void listFiles_DragDrop(object sender, DragEventArgs e)
        {
            string[] ss = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            Array.Sort(ss);
            appendFiles(ss);
        }
        private void listFiles_DoubleClick(object sender, EventArgs e)
        {
            openListFiles();
        }
        private void Got(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void listFiles_Lost(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void listFiles_Validated(object sender, EventArgs e)
        {
            repaintControls();
        }
        private void buttonReplace_Click(object sender, EventArgs e)
        {
            replaceAll();
        }
        private void initCharset()
        {
            string setName = Settings.Default.charset;
            int idx = -1;
            int def = -1;
            EncodingInfo[] encodingInfos = Encoding.GetEncodings();
            Array.Sort<EncodingInfo>(encodingInfos, new EncodingInfoNameComparers());
            comboCharset.Items.Clear();
            //comboCharset.DisplayMember = "DisplayName";
            comboCharset.DisplayMember = "Name";
            foreach (EncodingInfo encodingInfo in encodingInfos)
            {
                comboCharset.Items.Add(encodingInfo);
                if (idx == -1 && encodingInfo.Name.Equals(setName)){
                    idx = comboCharset.Items.Count - 1;
                    comboCharset.SelectedIndex = idx;
                }
                if(def == -1 && Encoding.Default.Equals(encodingInfo.GetEncoding()))
                {
                    def = comboCharset.Items.Count - 1;
                }
            }
            if (idx == -1)
            {
                if (def != -1)
                {
                    comboCharset.SelectedIndex = def;
                }
                else
                {
                    comboCharset.SelectedIndex = 0;
                }
            }
        }
        private void initControls()
        {
            checkNumber.Checked = Settings.Default.checkNumber;
            numericStart.Value = Settings.Default.numericStart;
            numericDigit.Value = Settings.Default.numericDigit;
            listFiles.Columns[0].Width = Settings.Default.columnName_width;
            listFiles.Columns[1].Width = Settings.Default.columnDate_width;
            listFiles.Columns[2].Width = Settings.Default.columnSize_width;
            listFiles.Columns[3].Width = Settings.Default.columnPath_width;
        }
        private void fitWidth(Control control)
        {
            control.Width = control.Parent.ClientSize.Width -
                (control.Parent.Padding.Left + control.Parent.Padding.Right) -
                (control.Margin.Left + control.Margin.Right);
        }
        private void repaintControls()
        {
            numericStart.Enabled = checkNumber.Checked;
            numericDigit.Enabled = checkNumber.Checked;
            repaintSample();
            buttonReplace.Enabled = listFiles.Items.Count > 0 && textFind.Text.Length > 0;
            menuReplace.Enabled = buttonReplace.Enabled;
            bool b = listFiles.Focused && listFiles.Enabled && listFiles.SelectedItems.Count > 0;
            menuOpen.Enabled = b;
            menuUp.Enabled = b;
            menuDown.Enabled = b;
            menuDelete.Enabled = b;
            repaintStatus();
        }
        private string getReplaceText(int number)
        {
            StringBuilder sb = new StringBuilder(textReplace.Text.Length + 10);
            sb.Append(textReplace.Text);
            if (checkNumber.Checked)
            {
                string s = "" + number;
                int n = 0, idx = 0;
                if (numericDigit.Value > s.Length)
                {
                    n = (int)numericDigit.Value - s.Length;
                }
                if (numericStart.Value < 0)
                {
                    sb.Append("-");
                    idx = 1;
                }
                for (int i = 0; i < n; i++)
                {
                    sb.Append("0");
                }
                sb.Append(s.Substring(idx));
                textSample.Text = sb.ToString();
            }
            return sb.ToString();
        }
        private void repaintSample()
        {
            if (checkNumber.Checked)
            {
                textSample.Text = getReplaceText((int)numericStart.Value);
            }
            textSample.Visible = checkNumber.Checked;
        }
        private void repaintStatus()
        {
            int selected = listFiles.SelectedItems.Count;
            int items = listFiles.Items.Count;
            string message = selected > 0 ? 
                Resources.Form1_Status1_Label1_M002 : 
                Resources.Form1_Status1_Label1_M001;
            message = message.Replace("{items}", "" + items);
            message = message.Replace("{selected}", "" + selected);
            toolStripStatusLabel1.Text = message;
        }
        private void appendFiles(string[] paths)
        {
            foreach (string path in paths)
            {
                appendFile(path);
            }
        }
        private void appendFile(string path)
        {
            try{
                FileInfo file = new FileInfo(path);
                string name = file.Name;
                DateTime time = file.LastWriteTime;
                long size = file.Length;

                ListViewItem item = new ListViewItem(name);
                item.SubItems.Add(time.ToString());
                System.Globalization.NumberFormatInfo numberFormatInfo = new System.Globalization.NumberFormatInfo();
                numberFormatInfo.NumberDecimalDigits = 0;
                item.SubItems.Add((size / 1024 + (size % 1024 > 0 ? 1 : 0)).ToString("N", numberFormatInfo) + " KB");
                item.SubItems.Add(path);
                listFiles.Items.Add(item);
                
            }catch(Exception e){
                Console.WriteLine("The process failed: {0}", e.ToString());

            }finally{
                repaintControls();
            }
        }
        private void replaceAll()
        {
            Cursor old = Cursor.Current;

            try
            {
                Cursor.Current = Cursors.WaitCursor;
                int count = 0, error = 0;
                int number = (int)numericStart.Value;
                textResult.Text = "";
                foreach (ListViewItem item in listFiles.Items)
                {
                    try
                    {
                        replace(item, ref number, ref count);
                        textResult.Text += item.SubItems[pathIndex].Text + "\r\n";
                        textResult.SelectionStart = textResult.Text.Length;
                        textResult.ScrollToCaret();
                    }
                    catch (Exception e)
                    {
                        error++;
                        textResult.Text += item.SubItems[pathIndex].Text + " " + Resources.Form1_TextResult_M001 + "\r\n";
                        textResult.Text += e.Message;
                        textResult.SelectionStart = textResult.Text.Length;
                        textResult.ScrollToCaret();
                        //Console.WriteLine(e.Message);
                    }
                }
                textResult.Text +=
                    Resources.Form1_TextResult_M002.Replace("{replaced}", "" + count).Replace("{error}", "" + error);
                textResult.SelectionStart = textResult.Text.Length;
                textResult.ScrollToCaret();
            }
            finally
            {
                Cursor.Current = old;
            }
        }
        private void replace(ListViewItem item, ref int value, ref int count)
        {
            int addCount = 0;
            //Console.WriteLine(item.SubItems[pathIndex()].Text);
            Encoding encoding = Encoding.Default;
            EncodingInfo encodingInfo = (EncodingInfo)comboCharset.SelectedItem;
            if(encodingInfo != null){
                encoding = encodingInfo.GetEncoding();
            }
            string source = read(item, encoding);
            string replaced = replace(source, ref value, ref addCount);
            write(item, encoding, replaced);
            count += addCount;
            Console.WriteLine(replaced.ToString());
        }
        private string read(ListViewItem item, Encoding encoding)
        {
            using (StreamReader stream = new StreamReader(item.SubItems[pathIndex].Text, Encoding.Default))
            {
                return stream.ReadToEnd();
            }
        }
        private void write(ListViewItem item, Encoding encoding, string text)
        {
            using (StreamWriter stream = new StreamWriter(item.SubItems[pathIndex].Text, false, encoding))
            {
                stream.Write(text);
            }
        }
        private string replace(string source, ref int value, ref int count)
        {
            int o = 0, r = 0;
            string search = textFind.Text, replace = textReplace.Text;
            StringBuilder ret = new StringBuilder();

            while (-1 != (r = source.IndexOf(search, o)))
            {
                ret.Append(source.Substring(o, r - o));
                ret.Append(getReplaceText(value++));
                count++;

                o = r + search.Length;
            }
            ret.Append(source.Substring(o));

            return ret.ToString();
        }
        private void openListFiles()
        {
            foreach (ListViewItem item in listFiles.SelectedItems)
            {
                try
                {
                    System.Diagnostics.Process.Start(item.SubItems[pathIndex].Text);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
        private int pathIndex
        {
            get
            {
                return 3;
            }
        }

        private void aboutReplaceToolToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.ShowDialog();
        }
        private IList<ListViewItem> copySelectedItems()
        {
            List<ListViewItem> result = new List<ListViewItem>();
            foreach (ListViewItem item in listFiles.SelectedItems)
            {
                result.Add(item);
            }
            return result;
        }
        private void changeItemPos(int x, int y)
        {
            if(x != y){
                int small = x < y ? x : y;
                int big = x < y ? y : x;
                ListViewItem smallItem = listFiles.Items[small];
                ListViewItem bigItem = listFiles.Items[big];
                listFiles.Items.RemoveAt(big);
                listFiles.Items.RemoveAt(small);
                listFiles.Items.Insert(small, bigItem);
                listFiles.Items.Insert(big, smallItem);
            }
        }
    }
}
